package com.redissdk.redis;

import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
  * 项目名称:[redisx]
  * 包:[com.redissdk.redis]    
  * 文件名称:[PowerfulRedisUtil]  
  * 描述:[Redis 工具类  - jedispool的使用]
  * 创建人:[陆文斌]
  * 创建时间:[2016年12月5日 下午5:48:45]   
  * 修改人:[陆文斌]   
  * 修改时间:[2016年12月5日 下午5:48:45]   
  * 修改备注:[说明本次修改内容]  
  * 版权所有:luwenbin006@163.com
  * 版本:[v1.0]
 */
public class PowerfulRedisUtil
{

    protected static Logger logger = Logger.getLogger(PowerfulRedisUtil.class);

    //Redis服务器IP  
    private static String ADDR_ARRAY = null;

    //Redis的端口号  
    private static int PORT = 0;

    //访问密码  
    private static String AUTH = null;

    //可用连接实例的最大数目，默认值为8；  
    //如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。  
    private static int MAX_ACTIVE = 0;

    //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8。  
    private static int MAX_IDLE = 0;

    //等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出JedisConnectionException；  
    private static int MAX_WAIT = 0;

    //超时时间  
    private static int TIMEOUT = 0;

    //在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；  
    private static boolean TEST_ON_BORROW = false;

   

    private static JedisPool jedisPool = null;

    /** 
     * redis过期时间,以秒为单位 
     */
    public final static int EXRP_HOUR = 60 * 60; //一小时  
    public final static int EXRP_DAY = 60 * 60 * 24; //一天  
    public final static int EXRP_MONTH = 60 * 60 * 24 * 30; //一个月  

    
    private static void initRedisConfigValue()
    {
        ADDR_ARRAY = FileUtil.getPropertyValue("properties/redis.properties",
                "master_server");

        PORT = FileUtil.getPropertyValueInt("properties/redis.properties",
                "master_port");
        AUTH = FileUtil.getPropertyValue("properties/redis.properties", "auth");
        MAX_ACTIVE = FileUtil.getPropertyValueInt(
                "properties/redis.properties", "max_active");
        ;
        MAX_IDLE = FileUtil.getPropertyValueInt("properties/redis.properties",
                "max_idle");
        ;
        MAX_WAIT = FileUtil.getPropertyValueInt("properties/redis.properties",
                "max_wait");
        ;
        TIMEOUT = FileUtil.getPropertyValueInt("properties/redis.properties",
                "timeout");
        ;
        TEST_ON_BORROW = FileUtil.getPropertyValueBoolean(
                "properties/redis.properties", "test_on_borrow");
        
        FileUtil.remove("properties/redis.properties");
    }
    /** 
     * 初始化Redis连接池 
     */
    private static void initialPool()
    {
        initRedisConfigValue();
        
        try
        {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(MAX_ACTIVE);
            config.setMaxIdle(MAX_IDLE);
            config.setMaxWaitMillis(MAX_WAIT);
            config.setTestOnBorrow(TEST_ON_BORROW);
            if (StringUtils.isEmpty(AUTH))
            {
                jedisPool = new JedisPool(config, ADDR_ARRAY.split(",")[0],
                        PORT, TIMEOUT);
            }
            else
            {
                jedisPool = new JedisPool(config, ADDR_ARRAY.split(",")[0],
                        PORT, TIMEOUT, AUTH);
            }

        }
        catch (Exception e)
        {
            logger.error("First create JedisPool error : " + e);
            try
            {
                //如果第一个IP异常，则访问第二个IP  
                JedisPoolConfig config = new JedisPoolConfig();
                config.setMaxTotal(MAX_ACTIVE);
                config.setMaxIdle(MAX_IDLE);
                config.setMaxWaitMillis(MAX_WAIT);
                config.setTestOnBorrow(TEST_ON_BORROW);
                if (StringUtils.isEmpty(AUTH))
                {
                    jedisPool = new JedisPool(config, ADDR_ARRAY.split(",")[1],
                            PORT, TIMEOUT);

                }
                else
                {
                    jedisPool = new JedisPool(config, ADDR_ARRAY.split(",")[1],
                            PORT, TIMEOUT, AUTH);
                }

            }
            catch (Exception e2)
            {
                logger.error("Second create JedisPool error : " + e2);
            }
        }
    }

    /** 
     * 在多线程环境同步初始化 
     */
    private static synchronized void poolInit()
    {
        if (jedisPool == null)
        {
            initialPool();
        }
    }

    /** 
     * 同步获取Jedis实例 
     * @return Jedis 
     */
    public synchronized static Jedis getJedis()
    {
        if (jedisPool == null)
        {
            poolInit();
        }
        Jedis jedis = null;
        try
        {
            if (jedisPool != null)
            {
                jedis = jedisPool.getResource();
            }
        }
        catch (Exception e)
        {
            returnBrokenResource(jedis);
            logger.error("Get jedis error : " + e);
        }
        
        return jedis;
    }

    /** 
     * 释放jedis资源 
     * @param jedis 
     */
    public static void returnResource(final Jedis jedis)
    {
        if (jedis != null && jedisPool != null)
        {
            jedisPool.returnResource(jedis);
        }
    }
    
    /** 
     * 出现异常的时候释放jedis资源 
     * @param jedis 
     */
    public static void returnBrokenResource(final Jedis jedis)
    {
        if (null !=  jedis && null != jedisPool)
        {
            jedisPool.returnBrokenResource(jedis);
        }
    }
    
    

    /** 
     * 设置 String 
     * @param key 
     * @param value 
     */
    public static String setString(String key, String value)
    {
        Jedis jedis = getJedis();
        String r_str = "nil";
        try
        {
            value = StringUtils.isEmpty(value) ? "" : value;
            r_str =  jedis.set(key, value);
        }
        catch (Exception e)
        {
            returnBrokenResource(jedis);
            logger.error("Set key error : " + e);
        }finally
        {
            returnResource(jedis);
        }
        
        return r_str;
    }

    /** 
     * 设置 过期时间 
     * @param key 
     * @param seconds 以秒为单位 
     * @param value 
     */
    public static String setString(String key, String value, int expirationTime)
    {
        Jedis jedis = getJedis();
        String r_str = "nil";
        try
        {
            value = StringUtils.isEmpty(value) ? "" : value;
            r_str=jedis.setex(key, expirationTime, value);
        }
        catch (Exception e)
        {
            returnBrokenResource(jedis);
            logger.error("Set keyex error : " + e);
        }finally
        {
            returnResource(jedis);
        }
        return r_str;
    }

    public static Set<byte[]> getKeys(byte[] keys)
    {
        Jedis jedis = getJedis();
        Set<byte[]> sets =  jedis.keys(keys);
        returnResource(jedis);
        return sets;
    }

    public static Set<String> getKeys(String keys)
    {
        Jedis jedis = getJedis();
        Set<String> sets =  jedis.keys(keys);
        returnResource(jedis);
        return sets;
    }

    public static Set<byte[]> hkeys(byte[] hkeys)
    {
        Jedis jedis = getJedis();
        Set<byte[]> sets =  jedis.hkeys(hkeys);
        returnResource(jedis);
        return sets;
    }

    public static Set<String> hkeys(String hkeys)
    {
        Jedis jedis = getJedis();
        Set<String> sets =  jedis.hkeys(hkeys);
        returnResource(jedis);
        return sets;
    }

    public static List<byte[]> hvals(byte[] hvals)
    {
        Jedis jedis = getJedis();
        List<byte[]> lists =  jedis.hvals(hvals);
        returnResource(jedis);
        return lists;
    }

    public static List<String> hvals(String hvals)
    {
        Jedis jedis = getJedis();
        List<String> lists =  jedis.hvals(hvals);
        returnResource(jedis);
        return lists;
    }

    /** 
     * 获取String值 
     * @param key 
     * @return value 
     */
    public static String getString(String key)
    {
        Jedis jedis = getJedis();
        String r_str=null;
        if (jedis == null || !jedis.exists(key))
        {
            returnResource(jedis);
            r_str = null;
        }else
        {
            r_str =  jedis.get(key);
            returnResource(jedis);
        }
        
        return r_str;
    }

    public static String setObject(String key, Object obj, int expirationTime)
    {
        Jedis jedis = getJedis();
        String r_str="nil";
        try
        {
            r_str = jedis.setex(key.getBytes(), expirationTime,
                    SerializationAndCompressUtils.fastSerialize(obj));

        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            returnBrokenResource(jedis);
            e.printStackTrace();
        }finally
        {
            returnResource(jedis);
        }
        return r_str;

    }

    public static String setObject(String key, Object obj)
    {
        Jedis jedis = getJedis();
        String r_str="nil";
        try
        {
            r_str = jedis.set(key.getBytes(),
                    SerializationAndCompressUtils.fastSerialize(obj));

        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            returnBrokenResource(jedis);
            e.printStackTrace();
        }finally
        {
            returnResource(jedis);
        }
        return r_str;

    }

    public static Long del(String key)
    {
        Jedis jedis = getJedis();
        Long r_l = 0l;
        try
        {
            r_l = jedis.del(key);

        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            returnBrokenResource(jedis);
            e.printStackTrace();
        }finally
        {
            returnResource(jedis);
        }
        return r_l;

    }

    public static Long del(byte[] key)
    {
        Jedis jedis = getJedis();
        Long r_l = 0l;
        try
        {
            r_l = jedis.del(key);

        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            returnBrokenResource(jedis);
            e.printStackTrace();
        }finally
        {
            returnResource(jedis);
        }
        return r_l;

    }

    public static Long del(byte[]... key)
    {
        Jedis jedis = getJedis();
        Long r_l = 0l;
        try
        {
            r_l = jedis.del(key);
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            returnBrokenResource(jedis);
            e.printStackTrace();
        }finally
        {
            returnResource(jedis);
        }
        return r_l;

    }

    /** 
     * 获取Object 
     * @param key 
     * @return 
     * @return value 
     */
    public static <T> T getObject(String key, Class<T> classz)
    {
        Jedis jedis = getJedis();
        T t = null;
        if ( jedis== null || !jedis.exists(key))
        {
            t =  null;
            returnResource(jedis);
        }else
        {
            byte[] value = jedis.get(key.getBytes());
            try
            {

                t = classz.cast(SerializationAndCompressUtils.fastDeserialize(value));

            }
            catch (Exception e)
            {
                // TODO Auto-generated catch block
                returnBrokenResource(jedis);
                e.printStackTrace();
            }finally {
                
                returnResource(jedis);
            }
        }
       

        return t;
    }

}